#pragma once
#include "LockGuard.hpp"
#include "thread.hpp"
#include<iostream>
#include <pthread.h>
#include<vector>
#include<queue>

const int g_thread_num=20;

template <class T>
class ThreadPool
{
public:
    pthread_mutex_t* getMutex(){
        return &_lock;
    }
    bool isEmpty(){
        return _task_queue.empty();
    }
    void WaitCond(){
        pthread_cond_wait(&_cond, nullptr);
    }
    T getTask(){
        T task=_task_queue.front();
        _task_queue.pop();
        return task;
    }
    static ThreadPool<T>* getThreadPool(int num=g_thread_num)
    {
        if(thread_ptr==nullptr){
            LockGuard lockguard(&_mutex);
            if(thread_ptr==nullptr){
                thread_ptr=new ThreadPool<T>(num);
            }
        }
        return thread_ptr;
    }
    void run()
    {
        //在这里让线程启动
        for(auto& iter:_threads){
            iter->Start();
        }
    }
    static void* ThreadRoutine(void* args)
    {
        ThreadData* td=(ThreadData*)args;
        ThreadPool<T>* tp=(ThreadPool<T>*)(td->_args);
        while(true)
        {
            T task;
            {
                LockGuard lockguard(tp->getMutex());
                while(tp->isEmpty()){
                    tp->WaitCond();
                }
                task=tp->getTask();
            }
            task(td->_name);
            // T task;
            // {
            //     LockGuard lockguard(&_lock);
            //     while(_task_queue.empty()){
            //         pthread_cond_wait(&_cond, nullptr);
            //     }
            //     //task;
            // }
        }
    }
    void pushTask(const T task){
        LockGuard lockguard(&_mutex);
        _task_queue.push(task);
        //条件满足以后就可以通知在这个条件下等待的线程来执行任务
        pthread_cond_signal(&_cond);
    }
private:
    ThreadPool(int thread_num=g_thread_num)
    :_num(thread_num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for(int i=0;i<_num;i++){
            //这里想要让线程访问线程池内的局部变量所以需要传递this指针才可以
            _threads.push_back(new Thread(i,ThreadRoutine,this));
        }
    }
    ThreadPool(const ThreadPool<T>& other)=delete;
    const ThreadPool<T>& operator=(const ThreadPool<T>&)=delete;
    
    std::vector<Thread*> _threads;
    int _num;
    std::queue<T> _task_queue;
    static ThreadPool<T>* thread_ptr;
    static pthread_mutex_t _mutex;

    pthread_mutex_t _lock;
    pthread_cond_t _cond;
};